/*!
    \file    udp_echo.c
    \brief   UDP demo program with communication statistics
*/

#include "main.h"
#include "lwip/opt.h"
#include "lwip/tcp.h"
#include "lwip/sys.h"
#include "udp_echo.h"
#include <string.h>
#include <stdio.h>
#include "gd32h7xx.h"
#include "lwip/memp.h"
#include "lwip/api.h"
#include "comm_stats.h"

#define UDP_TASK_PRIO       ( tskIDLE_PRIORITY + 5)
#define MAX_BUF_SIZE        50


#if ((LWIP_SOCKET == 0) && (LWIP_NETCONN == 1))

struct recev_packet {
    int length;
    char bytes[MAX_BUF_SIZE];
};

static err_t udp_echo_recv(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port);

/*!
    \brief      收到UDP数据时调用
    \param[in]  conn: UDP连接对象
    \param[in]  buf: 接收的数据缓冲区
    \param[in]  addr: 发送方IP地址
    \param[in]  port: 发送方端口
    \param[out] none
    \retval     err_t: 错误码
*/
static err_t udp_echo_recv(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port)
{
    struct pbuf *q;
    struct recev_packet recev_packet;
    uint32_t data_len = 0;
    struct netbuf *udpbuf;

    if(NULL != buf) {
        for(q = buf->p; q != NULL; q = q->next) {
            if(q->len > (MAX_BUF_SIZE - data_len)) {
                memcpy((recev_packet.bytes + data_len), q->payload, (MAX_BUF_SIZE - data_len));
                data_len = MAX_BUF_SIZE;
            } else {
                memcpy((recev_packet.bytes + data_len), q->payload, q->len);
                data_len += q->len;
            }
            if(data_len >= MAX_BUF_SIZE) break;
        }

        recev_packet.length = data_len;
        udpbuf = netbuf_new();
        netbuf_ref(udpbuf, recev_packet.bytes, recev_packet.length);
        netconn_sendto(conn, udpbuf, addr, port);
        netbuf_delete(udpbuf);
    }

    // 新增：通知统计系统（UDP通信）
    comm_stats_on_receive(COMM_TYPE_UDP);
    return ERR_OK;
}

/*!
    \brief      UDP回显任务
    \param[in]  arg: 未使用
    \param[out] none
    \retval     none
*/
static void udp_task(void *arg)
{
    struct netconn *conn;
    ip_addr_t ipaddr;
    struct netbuf *buf;
    err_t recv_err;

    IP4_ADDR(&ipaddr, IP_S_ADDR0, IP_S_ADDR1, IP_S_ADDR2, IP_S_ADDR3);

    conn = netconn_new(NETCONN_UDP);
    netconn_bind(conn, IP_ADDR_ANY, 1025);  // 绑定1025端口

    while(1) {
        recv_err = netconn_recv(conn, &buf);
        while(ERR_OK == recv_err) {
            udp_echo_recv(conn, buf, &ipaddr, 1025);
            netbuf_delete(buf);
            recv_err = netconn_recv(conn, &buf);
        }

        netconn_close(conn);
        netconn_delete(conn);
    }
}

#endif /* ((LWIP_SOCKET == 0) && (LWIP_NETCONN == 1)) */



#if LWIP_SOCKET
#include "lwip/sockets.h"

/*!
    \brief      UDP回显任务（Socket模式）
    \param[in]  arg: 未使用
    \param[out] none
    \retval     none
*/
static void udp_task(void *arg)
{
    int  ret, recvnum, sockfd = -1;
    int udp_port = 1025;
    struct sockaddr_in rmt_addr, bod_addr;
    char buf[100];
    u32_t len;
    ip_addr_t ipaddr;

    IP4_ADDR(&ipaddr, IP_S_ADDR0, IP_S_ADDR1, IP_S_ADDR2, IP_S_ADDR3);

    rmt_addr.sin_family = AF_INET;
    rmt_addr.sin_port = htons(udp_port);
    rmt_addr.sin_addr.s_addr = ipaddr.addr;

    bod_addr.sin_family = AF_INET;
    bod_addr.sin_port = htons(udp_port);
    bod_addr.sin_addr.s_addr = htons(INADDR_ANY);

    while(1) {
        sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(sockfd < 0) continue;

        ret = bind(sockfd, (struct sockaddr *)&bod_addr, sizeof(bod_addr));
        if(ret < 0) {
            lwip_close(sockfd);
            sockfd = -1;
            continue;
        }

        len = sizeof(rmt_addr);
        recvnum = recvfrom(sockfd, buf, MAX_BUF_SIZE, 0, (struct sockaddr *)&rmt_addr, &len);

        while(-1 != sockfd) {
            if(recvnum > 0) {
                sendto(sockfd, buf, recvnum, 0, (struct sockaddr *)&rmt_addr, sizeof(rmt_addr));
                
                // 新增：通知统计系统（UDP通信）
                comm_stats_on_receive(COMM_TYPE_UDP);
            }
            recvnum = recvfrom(sockfd, buf, MAX_BUF_SIZE, 0, (struct sockaddr *)&rmt_addr, &len);
        }

        lwip_close(sockfd);
    }
}

#endif /* LWIP_SOCKET */


/*!
    \brief      初始化UDP回显功能
    \param[in]  none
    \param[out] none
    \retval     none
*/
void udp_echo_init(void)
{
    xTaskCreate(udp_task, "UDP", DEFAULT_THREAD_STACKSIZE, NULL, UDP_TASK_PRIO, NULL);
}